using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TreeCraft2D : MonoBehaviour
{
    private List<Leaf2D> leaves;
    private List<Branch2D> branches;
    public static GameObject tree;
    private bool finished;
    private bool rendered;
    public static bool drawLeaves;
	// Crown
    private int leafNumber;
    private int volumeNumber;
    private Vector3[] leafCenter;
	// Ellipsoid
	private float[] leafRadiusH;
	private float[] leafRadiusV;
	private float[] density;
	private float[] offset;
	// Cone
	private float[] leafRadius;
	private float[] leafHeight;
	// Trunk
    private float trunkMinLength;
	private int trunkNumber;
	private float noPerturbationOffset;
	private int minAdjLeaves;
	// Branches
    public static float thickness;
    public static float growDist;
	public float tmpGrowDist;
    public float minDist;
    public float maxDist;
    public static Texture2D trunkTexture;
	// Mesh
    public int trunkSubdivisions = 6;
	
    public void GenerateTrunk(Vector3 pos)
    {
        // Add first branch (base of trunk)
        branches.Add(new Branch2D(pos, null, tree.transform, growDist, 6));
		
        for (int i = 1; i < 100; i++)
        {
            branches.Add(new Branch2D(pos + Vector3.up * growDist * i, branches[branches.Count - 1], tree.transform, growDist, 6));

            if (TrunkWithinLeaves(branches[i].location))
                break;
        }
    }

    public void Grow()
    {
        if(!finished)
        {
            for (int i = 0; i < leaves.Count; i++)
            {
				Leaf2D leaf = leaves[i];
                float lowestDist = maxDist;
                Vector3 lowestDir = new Vector3(0.0f, 0.0f, 0.0f);
                Branch2D closestBranch = null;
                for (int j = 0; j < branches.Count; j++)
                {
                    Branch2D branch = branches[j];
                    Vector3 dir = leaf.location - branch.location;
                    float dist = Vector3.Distance(leaf.location, branch.location);
                    if (dist > maxDist)
					{
                        continue;
					}
                    if (dist < minDist)
					{
                        leaves.Remove(leaf);
					}
                    if (closestBranch == null || dist <= lowestDist)
					{
                        closestBranch = branch;
					}
                    if (lowestDir == null || dist <= lowestDist)
					{
                        lowestDir = dir;
					}
                    if (dist <= lowestDist)
					{
                        lowestDist = dist;
					}

                }
                // We have the closest branch to that leaf
                if (closestBranch != null)
                {
                    closestBranch.growCount++;
                    lowestDir.Normalize();
                    closestBranch.growDir += lowestDir;
                }
            }

            finished = true;
            for (int i = branches.Count - 1; i > 0; i--)
            {
                Branch2D branch = branches[i];
                branch.Draw(thickness);
                if (branch.growCount > 0)
                {
                    finished = false;
                    branch.growDir /= branch.growCount;
                    branch.growDir.Normalize();
                    branch.growDir *= growDist;
                    Branch2D newBranch = new Branch2D(branch.location + branch.growDir, branch, tree.transform, growDist, 6);
                    branches.Add(newBranch);

                    branch.growDir = new Vector3(0.0f, 0.0f, 0.0f);
                    branch.growCount = 0;
                    branch.area = 0.0f;
                }
            }
            if (!finished)
                Grow();
            else
            {
                float tmp = Time.realtimeSinceStartup;
                CreateMesh();
                Debug.Log("Time for Mesh: " + (Time.realtimeSinceStartup - tmp).ToString("f6"));
            }
        }
    }

    void Start()
    {
        leaves = new List<Leaf2D>();
        branches = new List<Branch2D>();
        //tree = new GameObject("Tree");
		finished = false;
        rendered = false;
        drawLeaves = false;
        leafRadius = new float[7];
        leafHeight = new float[7];
        leafRadiusH = new float[7];
        leafRadiusV = new float[7];
        leafCenter = new Vector3[7];
        offset = new float[7];
        density = new float[7];
    }

    void Update()
    {
        //foreach (var branch in branches)
        /*if (!finished)
        {
            for (int i = branches.Count - 1; i > 0; i--)
            {
                Branch branch = branches[i];
                //if (branch.cone != null)
                //    DestroyImmediate(branch.cone.cone);
                branch.Draw(thickness);
                //branch.CreateGeometry();
                //if (drawLeaves)
                //    branch.DrawLeaves();
            }
            if (branches.Count != 0)
            {
                //Grow();
            }
        }*/
        if (finished && !rendered)
        {
            //CreateMesh();
            Debug.Log("Tree completed");
            rendered = true;
        }
        //if (Input.GetKeyDown("n"))
        //{
        //    rendered = false;

        //    growDist = Random.Range(1f, 1f);
        //    maxDist = Random.Range(3f, 3f); 
        //    minDist = Random.Range(2f, 2f); // Kill factor

        //    volumeNumber = Random.Range(1, 1);
        //    minAdjLeaves = Random.Range(1, 1);
        //    leafNumber = Random.Range(2000, 2000);
        //    density[0] = Random.Range(1f, 1.0f);
        //    offset[0] = Random.Range(1.0f, 1f);
        //    //density[2] = Random.Range(1f, 1.0f);
        //    //offset[2] = Random.Range(0.0f, 0f);
        //    /*leafRadiusH[0] = Random.Range(1.0f, 20.0f);
        //    leafRadiusV[0] = Random.Range(1.0f, 20.0f);
        //    leafCenter[0] = new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(1.0f, 12.0f), Random.Range(-0.5f, 0.5f));*/
        //    for (int i = 0; i < volumeNumber; i++)
        //    {
        //        leafRadiusH[i] = Random.Range(10f, 10f);
        //        leafRadiusV[i] = Random.Range(10f, 10f);
        //        //leafCenter[i] = new Vector3(Random.Range(-0f, 0f), Random.Range(0f /*+ i * 2.0f*/, 0f), Random.Range(-0f, 0f));
        //    }
        //    //leafRadiusH[2] = Random.Range(4f, 4f);
        //    //leafRadiusV[2] = Random.Range(12f, 12f);
        //    leafCenter[0] = new Vector3(0f, 0f, 0f);
        //    //leafCenter[2] = new Vector3(0f, 12f, 0f);
        //    thickness = Random.Range(0.025f, 0.025f);
        //    trunkNumber = Random.Range(1, 1);
        //    noPerturbationOffset = Random.Range(0.0f, 0.0f);

        //    Destroy(tree);
        //    tree = new GameObject("Tree");
        //    branches.Clear();
        //    leaves.Clear();

        //    branches.Add(new Branch(new Vector3(0f, leafCenter[0].y - maxDist, 0f), null, tree.transform, growDist, 6));
        //    branches.Add(new Branch(new Vector3(0f, leafCenter[0].y, 0f), branches[branches.Count - 1], tree.transform, growDist, 6));
        //    float temp = Time.realtimeSinceStartup;
        //    GenerateLeavesEllipsoid();
        //    Debug.Log("Time for Volume: " + (Time.realtimeSinceStartup - temp).ToString("f6"));
        //    //GenerateLeavesCone();
        //    //GenerateLeavesHeart();
        //    //GenerateLeavesCone();
        //    /*for (int i = 0; i < trunkNumber; i++)
        //    {
        //        GenerateTrunk(new Vector3(Random.Range(-0f, 0f), 0.0f, Random.Range(-0f, 0f)));
        //    }*/
			
        //    finished = false;
        //    //Debug.Log("Volume Completed");
        //    temp = Time.realtimeSinceStartup;
        //    Grow();
        //    Debug.Log("Time for Growth: " + (Time.realtimeSinceStartup - temp).ToString("f6"));
        //}
        //if (Input.GetKeyDown("f"))
        //{
        //    finished = !finished;
        //    Debug.Log("Stopped");
        //}
        //if (Input.GetKeyDown("l"))
        //{
        //    drawLeaves = !drawLeaves;
        //}
        //if (Input.GetKeyDown("c"))
        //{
        //    finished = true;
        //    Destroy(tree);
        //    tree = new GameObject("Tree");
        //    branches.Clear();
        //    leaves.Clear();
        //}
    }
	
	public void OnGUI()
	{
		GUILayout.Label("Rotate X: Left Mouse Button");
        GUILayout.Label("Rotate Y: Right Mouse Button");
        GUILayout.Label("Zoom: Scroll Wheel");
        GUILayout.Label("Generate Acacia: n");
        /*GUILayout.Label("Pause/Unpause: f");
        GUILayout.Label("Clear: c");*/
	}

    public bool TrunkWithinLeaves(Vector3 top)
    {
        int count = 0;
        foreach (var leaf in leaves)
        {
            if (Vector3.Distance(leaf.location, top) <= maxDist)
                count++;
        }
        if (count >= minAdjLeaves)
            return true;
        return false;
    }

    public void CreateMesh()
    {
        for (int j = branches.Count - 1; j > 0; j--)
        {
            Branch2D branch = branches[j];
            branch.FinalizeSegment();
            branch.CreateSpheres(6);
        }
        //MeshFilter[] meshFilters = tree.GetComponentsInChildren<MeshFilter>();
        MeshFilter[] meshFilters = tree.GetComponentsInChildren<MeshFilter>();
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];
        int i = 0;
        while (i < meshFilters.Length)
        {
            combine[i].mesh = meshFilters[i].sharedMesh;
            combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
            meshFilters[i].gameObject.active = false;
            i++;
        }
        tree.AddComponent<MeshFilter>();
        tree.AddComponent<MeshRenderer>();
        tree.transform.GetComponent<MeshFilter>().mesh = new Mesh();
        tree.transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
        tree.transform.GetComponent<MeshRenderer>().material.shader = Shader.Find("Nature/ats Soft Occlusion Bark");
        tree.transform.GetComponent<MeshRenderer>().material.SetTexture("_MainTex", Resources.Load("BigTree_bark_diffuse") as Texture);
        tree.transform.GetComponent<MeshRenderer>().material.SetTexture("_BumpMap", Resources.Load("BigTree_bark_normal") as Texture);
        //tree.transform.gameObject.active = true;
    }
}
